#include "cJSON.h"
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#define PRINT_ERR(s)                         \
    do {                                     \
        fprintf(stderr, "__%d__", __LINE__); \
        perror(s);                           \
        return -1;                           \
    } while (0)

#define PORT 8888
#define IP "192.168.1.250"
#define SEG_DAT _IOW('k', 1, int)
#define GET_SI7006_TMEP _IOR('a', 0, int)
#define GET_SI7006_HUM _IOR('a', 1, int)
#define SET_FAN_PWM _IOR('f', 1, int)
#define SET_MATOR_PWM _IOR('m', 1, int)
#define SET_BEEP_PWM _IOR('b', 1, int)
#define SET_LED1 _IOR('l', 1, int)
#define SET_LED2 _IOR('l', 2, int)
#define SET_LED3 _IOR('l', 3, int)
char cname[][16] = { "si7006", "m74hc595" };
#define CNAMEN (sizeof(cname) / sizeof((cname)[0]))
int fd[CNAMEN] = { 0 };
enum cname {
    SI7006,
    M74HC595
};
int cli_fd;
int tcp_init();
int open_dev();
void send_handler(void* args);
int main(int argc, const char* argv[])
{
    cli_fd = tcp_init();
    if (cli_fd < 1)
        return -1;

    open_dev();
    int fd_pwm = open("dev/pwm-fan", O_RDWR);
    if (fd_pwm < 0)
        PRINT_ERR("open");
    int fd_led = open("dev/myled", O_RDWR);
    if (fd_led < 0)
        PRINT_ERR("open");
    char buf[64];
    ssize_t res = 0;
    int temp, hum, num;
    pthread_t tid;
    pthread_create(&tid, NULL, (void*)send_handler, NULL);
    while (1) {

        bzero(buf, sizeof(buf));
        res = recv(cli_fd, buf, sizeof(buf), 0);
        if (res == 0) {
            printf("连接断开\n");
            break;
        }
        cJSON* json = cJSON_Parse(buf);
        if (!json||!json->child) {
            continue;
        }
        num = json->child->valueint;
        if(!strcmp(json->child->string,"fan")){
            ioctl(fd_pwm, SET_FAN_PWM, num);
        }
        if(!strcmp(json->child->string,"beep")){
            ioctl(fd_pwm, SET_BEEP_PWM, num);
        }
        if(!strcmp(json->child->string,"mator")){
            ioctl(fd_pwm, SET_MATOR_PWM, num);
        }
        if(!strcmp(json->child->string,"LED1")){
            ioctl(fd_led, SET_LED1, num);
        }
        if(!strcmp(json->child->string,"LED2")){
            ioctl(fd_led, SET_LED2, num);
        }
        if(!strcmp(json->child->string,"LED3")){
            ioctl(fd_led, SET_LED3, num);
        }
        cJSON_Delete(json);
        
    }

    // 关闭套接字
    close(cli_fd);
    close(fd_pwm);
    close(fd_led);
    for (int i = 0; i < CNAMEN; i++) {
        close(fd[i]);
    }
    return 0;
}
void send_handler(void* args)
{

    char buf[64];
    ssize_t res = 0;
    int temp, hum, dat, pwm;
    while (1) {
        ioctl(fd[SI7006], GET_SI7006_HUM, &hum);
        ioctl(fd[SI7006], GET_SI7006_TMEP, &temp);
        hum = 125 * hum / 65536 - 6;
        temp = 176 * temp / 65536 - 47;
        dat = temp * 100 + hum;
        ioctl(fd[M74HC595], SEG_DAT, dat);
        // 发送数据
        bzero(buf, sizeof(buf));
        sprintf(buf, "{\n\"temp\":%d,\n\"hum\":%d\n}", temp, hum);
        if (send(cli_fd, buf, sizeof(buf), 0) < 0)
            puts("send is error");
            sleep(1);
    }
}
int open_dev()
{
    // 打开字符设备文件
    char name[32] = "";
    for (int i = 0; i < CNAMEN; i++) {
        bzero(name, sizeof(name));
        sprintf(name, "/dev/%s", cname[i]);
        fd[i] = open(name, O_RDWR);
        if (fd[i] < 0)
            PRINT_ERR("open");
    }
}
int tcp_init()
{
    // 创建流式套接字
    int cfd = socket(AF_INET, SOCK_STREAM, 0);
    if (cfd < 0)
        PRINT_ERR("socket");
    // 允许端口快速复用
    int reuse = 1;
    if (setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
        PRINT_ERR("setsockopt");

    // 连接服务器
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT);
    sin.sin_addr.s_addr = inet_addr(IP);
    if (connect(cfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
        PRINT_ERR("connect");
    puts("连接服务器成功");

    return cfd;
}